package com.aceitunaproject.clientinterface.listener;

import java.io.IOException;
import java.net.PasswordAuthentication;
import java.nio.ByteBuffer;

import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.aceitunaproject.clientinterface.AceitunaClientInterface;
import com.aceitunaproject.shared.message.AceitunaSender;
import com.aceitunaproject.shared.message.Message;
import com.aceitunaproject.shared.message.MessageConstants;
import com.aceitunaproject.shared.message.MessageSender;
import com.aceitunaproject.shared.message.MessageSenderImpl;
import com.sun.sgs.client.ClientChannel;
import com.sun.sgs.client.ClientChannelListener;
import com.sun.sgs.client.simple.SimpleClient;
import com.sun.sgs.client.simple.SimpleClientListener;
import com.sun.sgs.impl.sharedutil.MessageBuffer;
import com.sun.sgs.protocol.simple.SimpleSgsProtocol;

/**
 * @author Federico Bergstein
 * 
 *         This class handles the actual communication with the server.
 */
public class DefaultListener implements SimpleClientListener, AceitunaSender {

	// TODO: get properties from file
	/** The name of the host property. */
	public static final String HOST_PROPERTY = "aceituna.host";

	/** The default hostname. */
	public static final String DEFAULT_HOST = "localhost";

	/** The name of the port property. */
	public static final String PORT_PROPERTY = "aceituna.port";

	/** The default port. */
	public static final String DEFAULT_PORT = "62964";//62964

	/**
	 * the aceituna client interface that will accept the event messages
	 */
	private AceitunaClientInterface clientInterface;

	/**
	 * The Aceituna Message Sender
	 */
	private MessageSender messageSender = new MessageSenderImpl(this);

	/** The {@link SimpleClient} instance for this client. */
	protected final SimpleClient simpleClient;

	/**
	 * Class constructor
	 * 
	 */
	public DefaultListener(AceitunaClientInterface clientInterface) {
		this.clientInterface = clientInterface;
		simpleClient = new SimpleClient(this);

		// HashMap<String, Method> handler = new HashMap<String, Function>();

	}

	/**
	 * Initiates asynchronous login to the SGS server specified by the host and
	 * port properties.
	 */
	public void login() {
		String host = System.getProperty(HOST_PROPERTY, DEFAULT_HOST);
		String port = System.getProperty(PORT_PROPERTY, DEFAULT_PORT);

		try {
			Properties connectProps = new Properties();
			connectProps.put("host", host);
			connectProps.put("port", port);
			simpleClient.login(connectProps);
		} catch (Exception e) {
			e.printStackTrace();
			disconnected(false, e.getMessage());
		}
	}

	/**
	 * Logs out from the server
	 */
	public void logout() {
		simpleClient.logout(false);
		//TODO: check darkstar doc for meaning of boolean parameter

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.sun.sgs.client.simple.SimpleClientListener#getPasswordAuthentication
	 * ()
	 */
	
	public PasswordAuthentication getPasswordAuthentication() {
		// TODO: replace with real authentication method.
		String password = "guest";
		return new PasswordAuthentication(clientInterface.getPlayer(), password
				.toCharArray());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sun.sgs.client.simple.SimpleClientListener#loggedIn()
	 */
	
	public void loggedIn() {
		clientInterface.loggedIn();

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.sun.sgs.client.simple.SimpleClientListener#loginFailed(java.lang.
	 * String)
	 */
	
	public void loginFailed(String arg0) {
		clientInterface.loginFailed(arg0);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sun.sgs.client.ServerSessionListener#disconnected(boolean,
	 * java.lang.String)
	 */
	
	public void disconnected(boolean arg0, String arg1) {
		clientInterface.disconnected(arg0, arg1);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.sun.sgs.client.ServerSessionListener#joinedChannel(com.sun.sgs.client
	 * .ClientChannel)
	 */
	
	public ClientChannelListener joinedChannel(ClientChannel arg0) {
		// TODO Implement Channel management
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.sun.sgs.client.ServerSessionListener#receivedMessage(java.nio.ByteBuffer
	 * )
	 */
	
	public void receivedMessage(ByteBuffer message) {

		int messageType = message.get();

		if (messageType == MessageConstants.TYPE_BINARY) {
			// TODO: handle
			Logger.getLogger(this.getClass().getName()).log(Level.WARNING,
					"Binary Message received");
		} else {

			byte[] buffer = new byte[message.remaining()];
			message.get(buffer);

			Message deserializedMessage = (Message) ClientConfiguration
					.getObjectSerializer().deserialize(buffer);

			clientInterface.processMessage(deserializedMessage);
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sun.sgs.client.ServerSessionListener#reconnected()
	 */
	
	public void reconnected() {
		clientInterface.reconnected();

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sun.sgs.client.ServerSessionListener#reconnecting()
	 */
	
	public void reconnecting() {
		clientInterface.reconnecting();

	}

	/**
	 * Sends the given object message to the server
	 * 
	 * @param message
	 *            message to send
	 */
	public void sendObjectMessage(Message message) {

		messageSender.sendMessage(message);
	}

	/**
	 * Sends a message to the server
	 */
	public void sendMessage(ByteBuffer message) {

		MessageBuffer buf = new MessageBuffer(1 + message.remaining());
		buf.putByte(SimpleSgsProtocol.SESSION_MESSAGE)
				.putBytes(message.array());
		try {
			simpleClient.send(message);

		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

}
